package com.ztky.report.controller;

import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.export.HtmlExporter;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.ooxml.JRDocxExporter;
import net.sf.jasperreports.engine.util.FileBufferedOutputStream;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.export.SimpleDocxExporterConfiguration;
import net.sf.jasperreports.export.SimpleExporterInput;
import net.sf.jasperreports.export.SimpleHtmlExporterOutput;
import net.sf.jasperreports.export.SimpleOutputStreamExporterOutput;
import net.sf.jasperreports.j2ee.servlets.ImageServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * jasper基类
 *
 * @author liuji
 */
public abstract class JasperBaseController {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    DataSource dataSource;
    /**
     * 报表文件根目录，以/结尾
     */
    @Value("${report.root.dir}")
    private String reportRootDir;

    private String getAbsParentPath(File file) {
        if (file == null) {
            return "";
        }
        return file.getParentFile().getAbsolutePath() + "/";
    }

    /**
     * 基础数据构建
     *
     * @param request
     * @param response
     * @param relativeFileName 报表文件相对路径
     * @param parameters       参数集
     * @return
     * @throws JRException
     * @throws SQLException
     */
    private JasperPrint buildBase(HttpServletRequest request, HttpServletResponse response, String relativeFileName,
                                  Map<String, Object> parameters) throws JRException, SQLException {

        File reportFile = new File(reportRootDir + relativeFileName);
        if (!reportFile.exists())
            throw new JRRuntimeException("报表文件未找到. 请先编译成.jasper文件.");

        JasperReport jasperReport = (JasperReport) JRLoader.loadObjectFromFile(reportFile.getPath());
        //报表内嵌套引用其它报表需要传入文件的绝对路径，不然会报找不到对应报表
        parameters.put("BaseDir", getAbsParentPath(reportFile));

        JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource.getConnection());
        request.getSession().setAttribute(ImageServlet.DEFAULT_JASPER_PRINT_SESSION_ATTRIBUTE, jasperPrint);
        return jasperPrint;

    }

    /**
     * 输出HTML报表
     *
     * @param request
     * @param response
     * @param relativeFileName 模板文件相对路径
     * @param parameters       参数集
     * @throws ServletException
     * @throws SQLException
     * @throws IOException
     * @throws JRException
     */
    public void html(HttpServletRequest request, HttpServletResponse response, String relativeFileName,
                     Map<String, Object> parameters) throws ServletException, SQLException, IOException, JRException {

        response.setHeader("Content-type", "text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        JasperPrint jasperPrint = buildBase(request, response, relativeFileName, parameters);
        HtmlExporter exporter = new HtmlExporter();
        exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
        SimpleHtmlExporterOutput output = new SimpleHtmlExporterOutput(out);
        exporter.setExporterOutput(output);
        exporter.exportReport();

    }

    /**
     * 输出PDF
     *
     * @param request
     * @param response
     * @param relativeFileName 模板文件相对路径
     * @param parameters       参数集
     * @param outputFileName   输出文件名（带后缀名）
     * @throws ServletException
     * @throws SQLException
     * @throws IOException
     * @throws JRException
     */
    public void pdf(HttpServletRequest request, HttpServletResponse response, String relativeFileName,
                    Map<String, Object> parameters, String outputFileName)
            throws ServletException, SQLException, IOException, JRException {

        JasperPrint jasperPrint = buildBase(request, response, relativeFileName, parameters);

        FileBufferedOutputStream fbos = new FileBufferedOutputStream();
        JRPdfExporter exporter = new JRPdfExporter(DefaultJasperReportsContext.getInstance());
        exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
        exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(fbos));
        try {
            exporter.exportReport();
            fbos.close();

            if (fbos.size() > 0) {
                response.setContentType("application/pdf");
                response.setHeader("Content-Disposition", "inline; filename=\"" + outputFileName + "\"");
                response.setContentLength(fbos.size());
                ServletOutputStream outputStream = response.getOutputStream();

                try {
                    fbos.writeData(outputStream);
                    fbos.dispose();
                    outputStream.flush();
                } finally {
                    if (outputStream != null) {
                        try {
                            outputStream.close();
                        } catch (IOException ex) {
                        }
                    }
                }
            }
        } catch (JRException e) {
            throw new ServletException(e);
        } finally {
            fbos.close();
            fbos.dispose();
        }

    }

    /**
     * 输出Word
     *
     * @param request
     * @param response
     * @param relativeFileName 模板文件相对路径
     * @param parameters       参数集
     * @param outputFileName   输出文件名（带后缀名）
     * @throws ServletException
     * @throws SQLException
     * @throws IOException
     * @throws JRException
     */
    public void word(HttpServletRequest request, HttpServletResponse response, String relativeFileName,
                     Map<String, Object> parameters, String outputFileName)
            throws ServletException, SQLException, IOException, JRException {
        JasperPrint jasperPrint = buildBase(request, response, relativeFileName, parameters);
        List<JasperPrint> jasperPrintList = new ArrayList<>();
        jasperPrintList.add(jasperPrint);
        response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
        response.setHeader("Content-Disposition", "inline; filename=\"" + outputFileName + "\"");

        JRDocxExporter exporter = new JRDocxExporter(DefaultJasperReportsContext.getInstance());
        exporter.setExporterInput(SimpleExporterInput.getInstance(jasperPrintList));
        exporter.setConfiguration(new SimpleDocxExporterConfiguration());
        OutputStream outputStream = response.getOutputStream();
        exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(outputStream));

        try {
            exporter.exportReport();
        } catch (JRException e) {
            throw new ServletException(e);
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException ex) {
                }
            }
        }
    }
}
